home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / telecomm / sticpsrc.lzh / SOURCE.ARC / UDP.C < prev    next >
C/C++ Source or Header  |  1988-12-05  |  6KB  |  267 lines

  1. /* Send and receive User Datagram Protocol packets */
  2. #include "global.h"
  3. #include "mbuf.h"
  4. #include "netuser.h"
  5. #include "udp.h"
  6. #include "internet.h"
  7.  
  8. /* Hash table for UDP structures */
  9. struct udp_cb *udps[NUDP] = { NULLUDP} ;
  10. struct udp_stat udp_stat;    /* Statistics */
  11.  
  12. /* Create a UDP control block for lsocket, so that we can queue
  13.  * incoming datagrams.
  14.  */
  15. int
  16. open_udp(lsocket,r_upcall)
  17. struct socket *lsocket;
  18. void (*r_upcall)();
  19. {
  20.     register struct udp_cb *up;
  21.     struct udp_cb *lookup_udp();
  22.     int16 hval,hash_udp();
  23.  
  24.     if((up = lookup_udp(lsocket)) != NULLUDP)
  25.         return 0;    /* Already exists */
  26.     if((up = (struct udp_cb *)malloc(sizeof (struct udp_cb))) == NULLUDP){
  27.         net_error = NO_SPACE;
  28.         return -1;
  29.     }
  30.     up->rcvq = NULLBUF;
  31.     up->rcvcnt = 0;
  32.     up->socket.address = lsocket->address;
  33.     up->socket.port = lsocket->port;
  34.     up->r_upcall = r_upcall;
  35.  
  36.     hval = hash_udp(lsocket);
  37.     up->next = udps[hval];
  38.     up->prev = NULLUDP;
  39.     if(up->next != NULLUDP)
  40.         up->next->prev = up;
  41.     udps[hval] = up;
  42.     return 0;
  43. }
  44.  
  45. /* Send a UDP datagram */
  46. int
  47. send_udp(lsocket,fsocket,tos,ttl,data,length,id,df)
  48. struct socket *lsocket;        /* Source socket */
  49. struct socket *fsocket;        /* Destination socket */
  50. char tos;            /* Type-of-service for IP */
  51. char ttl;            /* Time-to-live for IP */
  52. struct mbuf *data;        /* Data field, if any */
  53. int16 length;            /* Length of data field */
  54. int16 id;            /* Optional ID field for IP */
  55. char df;            /* Don't Fragment flag for IP */
  56. {
  57.     struct mbuf *htonudp(),*bp;
  58.     struct pseudo_header ph;
  59.     struct udp udp;
  60.  
  61.     length = UDPHDR;
  62.     if(data != NULLBUF)
  63.         length += len_mbuf(data);
  64.  
  65.     udp.source = lsocket->port;
  66.     udp.dest = fsocket->port;
  67.     udp.length = length;
  68.  
  69.     /* Create IP pseudo-header, compute checksum and send it */
  70.     ph.length = length;
  71.     ph.source = lsocket->address;
  72.     ph.dest = fsocket->address;
  73.     ph.protocol = UDP_PTCL;
  74.  
  75.     if((bp = htonudp(&udp,data,&ph)) == NULLBUF){
  76.         net_error = NO_SPACE;
  77.         free_p(data);
  78.         return 0;
  79.     }
  80.     udp_stat.sent++;
  81.     ip_send(lsocket->address,fsocket->address,UDP_PTCL,tos,ttl,bp,length,id,df);
  82.     return length;
  83. }
  84.  
  85. /* Accept a waiting datagram, if available. Returns length of datagram */
  86. int
  87. recv_udp(lsocket,fsocket,bp)
  88. struct socket *lsocket;        /* Local socket to receive on */
  89. struct socket *fsocket;        /* Place to stash incoming socket */
  90. struct mbuf **bp;            /* Place to stash data packet */
  91. {
  92.     struct udp_cb *lookup_udp();
  93.     register struct udp_cb *up;
  94.     struct socket *sp;
  95.     struct mbuf *buf;
  96.     int16 length;
  97.  
  98.     up = lookup_udp(lsocket);
  99.     if(up == NULLUDP){
  100.         net_error = NO_CONN;
  101.         return -1;
  102.     }
  103.     if(up->rcvcnt == 0){
  104.         net_error = WOULDBLK;
  105.         return -1;
  106.     }
  107.     buf = dequeue(&up->rcvq);
  108.     up->rcvcnt--;
  109.  
  110.     sp = (struct socket *)buf->data;
  111.     /* Fill in the user's foreign socket structure, if given */
  112.     if(fsocket != NULLSOCK){
  113.         fsocket->address = sp->address;
  114.         fsocket->port = sp->port;
  115.     }
  116.     /* Strip socket header and hand data to user */
  117.     pullup(&buf,NULLCHAR,sizeof(struct socket));
  118.     length = len_mbuf(buf);
  119.     if(bp != (struct mbuf **)NULL)
  120.         *bp = buf;
  121.     else
  122.         free_p(buf);
  123.     return length;
  124. }
  125. /* Delete a UDP control block */
  126. int
  127. del_udp(lsocket)
  128. struct socket *lsocket;
  129. {
  130.     register struct udp_cb *up;
  131.     struct udp_cb *lookup_udp();
  132.     struct mbuf *bp;
  133.     int16 hval,hash_udp();
  134.  
  135.     if((up = lookup_udp(lsocket)) == NULLUDP){
  136.         net_error = INVALID;
  137.         return -1;
  138.     }
  139.     /* Get rid of any pending packets */
  140.     while(up->rcvcnt != 0){
  141.         bp = up->rcvq;
  142.         up->rcvq = up->rcvq->anext;
  143.         free_p(bp);
  144.         up->rcvcnt--;
  145.     }
  146.     hval = hash_udp(&up->socket);
  147.     if(udps[hval] == up)        /* First on list */
  148.         udps[hval] = up->next;
  149.     if(up->prev != NULLUDP)
  150.         up->prev->next = up->next;
  151.     if(up->next != NULLUDP)
  152.         up->next->prev = up->prev;
  153.  
  154.     free((char *)up);
  155.     return 0;
  156. }
  157. /* Process an incoming UDP datagram */
  158. void
  159. udp_input(bp,protocol,source,dest,tos,length,rxbroadcast)
  160. struct mbuf *bp;    /* UDP header and data */
  161. char protocol;        /* Should always be 17 */
  162. int32 source;        /* Source IP address */
  163. int32 dest;        /* Dest IP address */
  164. char tos;
  165. int16 length;
  166. char rxbroadcast;    /* The only protocol that accepts 'em */
  167. {
  168.     struct pseudo_header ph;
  169.     struct udp udp;
  170.     struct udp_cb *up,*lookup_udp();
  171.     struct socket lsocket;
  172.     struct socket *fsocket;
  173.     struct mbuf *packet;
  174.     int ckfail = 0;
  175.  
  176.     if(bp == NULLBUF)
  177.         return;
  178.  
  179.     udp_stat.rcvd++;
  180.  
  181.     /* Create pseudo-header and verify checksum */
  182.     ph.source = source;
  183.     ph.dest = dest;
  184.     ph.protocol = protocol;
  185.     ph.length = length;
  186.  
  187.     if(cksum(&ph,bp,length) != 0)
  188.         /* Checksum apparently failed, note for later */
  189.         ckfail++;
  190.  
  191.     /* Extract UDP header in host order */
  192.     ntohudp(&udp,&bp);
  193.  
  194.     /* If the checksum field is zero, then ignore a checksum error.
  195.      * I think this is dangerously wrong, but it is in the spec.
  196.      */
  197.     if(ckfail && udp.checksum != 0){
  198.         udp_stat.cksum++;
  199.         free_p(bp);
  200.         return;
  201.     }
  202.     /* If this was a broadcast packet, pretend it was sent to us */
  203.     if(rxbroadcast){
  204.         lsocket.address = ip_addr;
  205.         udp_stat.bdcsts++;
  206.     } else
  207.         lsocket.address = dest;
  208.  
  209.     lsocket.port = udp.dest;
  210.     /* See if there's somebody around to read it */
  211.     if((up = lookup_udp(&lsocket)) == NULLUDP){
  212.         /* Nope, toss it on the floor */
  213.         udp_stat.unknown++;
  214.         free_p(bp);
  215.         return;
  216.     }
  217.     /* Create space for the foreign socket info */
  218.     if((packet = pushdown(bp,sizeof(struct socket))) == NULLBUF){
  219.         /* No space, drop whole packet */
  220.         free_p(bp);
  221.         return;
  222.     }
  223.     fsocket = (struct socket *)packet->data;
  224.     fsocket->address = source;
  225.     fsocket->port = udp.source;
  226.  
  227.     /* Queue it */
  228.     enqueue(&up->rcvq,packet);
  229.     up->rcvcnt++;
  230.     if(up->r_upcall)
  231.         (*up->r_upcall)(&lsocket,up->rcvcnt);
  232. }
  233. /* Look up UDP socket, return control block pointer or NULLUDP if nonexistant */
  234. static
  235. struct udp_cb *
  236. lookup_udp(socket)
  237. struct socket *socket;
  238. {
  239.     register struct udp_cb *up;
  240.     int16 hash_udp();
  241.  
  242.     up = udps[hash_udp(socket)];
  243.     while(up != NULLUDP){
  244.         if(memcmp((char *)socket,(char *)&up->socket,sizeof(struct socket)) == 0)
  245.             break;
  246.         up = up->next;
  247.     }
  248.     return up;
  249. }
  250.  
  251. /* Hash a UDP socket (address and port) structure */
  252. static
  253. int16
  254. hash_udp(socket)
  255. struct socket *socket;
  256. {
  257.     int16 hval;
  258.  
  259.     /* Compute hash function on socket structure */
  260.     hval = hiword(socket->address);
  261.     hval ^= loword(socket->address);
  262.     hval ^= socket->port;
  263.     hval %= NUDP;
  264.     return hval;
  265. }
  266.  
  267.